/**
 * 通用的双向链表
 */

export class GenericLinkedListNode<T> {
    public prev: GenericLinkedListNode<T> | null = null;
    public next: GenericLinkedListNode<T> | null = null;
    constructor(public data: T) {}
}

export class GenericLinkedList<T> {
    private _head: GenericLinkedListNode<T> | null = null;
    private _tail: GenericLinkedListNode<T> | null = null;
    private _size: number = 0;

    public get head(): GenericLinkedListNode<T> | null {
        return this._head;
    }

    public get tail(): GenericLinkedListNode<T> | null {
        return this._tail;
    }

    public get size(): number {
        return this._size;
    }

    public isEmpty(): boolean {
        return this._size === 0;
    }

    public addFirst(data: T): GenericLinkedListNode<T> {
        const node = new GenericLinkedListNode(data);
        if (this.isEmpty()) {
            this._head = this._tail = node;
        } else {
            node.next = this._head;
            this._head!.prev = node;
            this._head = node;
        }
        this._size++;
        return node;
    }

    public addLast(data: T): GenericLinkedListNode<T> {
        const node = new GenericLinkedListNode(data);
        if (this.isEmpty()) {
            this._head = this._tail = node;
        } else {
            node.prev = this._tail;
            this._tail!.next = node;
            this._tail = node;
        }
        this._size++;
        return node;
    }

    public remove(node: GenericLinkedListNode<T>): void {
        if (!node) return;

        if (node.prev) {
            node.prev.next = node.next;
        } else {
            this._head = node.next;
        }

        if (node.next) {
            node.next.prev = node.prev;
        } else {
            this._tail = node.prev;
        }

        node.prev = null;
        node.next = null;
        this._size--;
    }

    public clear(): void {
        this._head = null;
        this._tail = null;
        this._size = 0;
    }

    public forEach(callback: (node: GenericLinkedListNode<T>) => void): void {
        let current = this._head;
        while (current) {
            callback(current);
            current = current.next;
        }
    }
}